#pragma once

namespace vex {
    /// <summary>
    /// Send the content of a smart pointer as an output parameter 
    /// to the callee according to vex reference counting rules. 
    /// The input parameter must be an l-value.
    /// </summary>
    /// 
    /// <param name="p_pointer">
    /// Instance of a smart pointer the content of which should be send as an output parameter
    /// </param>
    /// Extracts the resource, increments the reference count and returns the resource as raw pointer. 
    /// Since <paramref name="p_pointer"/> is passed by reference, no additional modifications 
    /// of the reference count will occur.
    /// Accepts any types which conform to c++ standard library "smart pointer" concept,
    /// i.e. it also accepts the "any_" wrappers defined by the Vex libraries.
    template<class TSmartPtr> auto as_raw_out(TSmartPtr& p_pointer)
        -> typename TSmartPtr::element_type*
    {
        if (p_pointer) {
            p_pointer->add_ref();
            //7 this should be an unqualified call to: get_pointer(p_pointer);
            return p_pointer.get();
        }

        return nullptr;
    }

    /// <summary>
    /// Send the content of a smart pointer as an input parameter 
    /// to the callee according to vex reference counting rules.
    /// </summary>
    /// 
    /// <param name="p_pointer">
    /// Instance of a smart pointer the content of which should be send as an input parameter
    /// </param>
    ///
    /// Extracts and returns the resource as raw pointer. 
    /// Since <paramref name="p_pointer"/> is passed by reference, no additional modifications 
    /// of the reference count will occur.
    /// Accepts any types which conform to c++ standard library "smart pointer" concept,
    /// i.e. it also accepts the "any_" wrappers defined by the Vex libraries.
    template<class TSmartPtr> auto as_raw_in(TSmartPtr const & p_pointer)
        -> typename TSmartPtr::element_type*
    {
        return p_pointer.get();
    }

    /// <summary>
    /// Pass a managed resource as an output parameter according to vex reference counting rules. 
    /// The input parameter must be an l-value.
    /// </summary>
    ///
    /// <param name="p_handle">
    /// Raw contract pointer to send. Must be a model of handle.
    /// </param>
    //template<class THandle> auto as_raw_out(THandle*& p_handle)
    //    -> THandle*
    //{
    //    if (p_handle) {
    //        p_handle->add_ref();
    //        return p_handle;
    //    }

    //    return nullptr;
    //}

    /// <summary>
    /// Send the resource pointer as an input parameter 
    /// to the callee according to vex reference counting rules.
    /// An identitity transformation.
    /// </summary>
    template<class THandle> auto as_raw_in(THandle* p_handle)
        -> THandle*
    {
        return p_handle;
    }
}